using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

using LongNet.Util;

namespace LongNet.Config
{
    /// <summary>
    /// An image helper to make/save thumbnail and water image.
    /// This class cannot be inherited.
    /// </summary>
    public static class ImageUtils
    {
        /// <summary>
        /// Gets the <see cref="System.Drawing.Imaging.ImageFormat"/> from a specified file name.
        /// The supported file extensions are jpg, jpeg, gif, png, bmp, ico, by default it returns 
        /// System.Drawing.Imaging.ImageFormat.Jpeg.
        /// </summary>
        /// <param name="fileName">A file name.</param>
        /// <returns>The <see cref="System.Drawing.Imaging.ImageFormat"/> associated with the file name.</returns>
        public static ImageFormat GetImageFormat(string fileName)
        {
            if (fileName.IsNullOrEmpty())
                throw new ArgumentException("The fileName is null or empty.", "fileName");

            int index = fileName.LastIndexOf(".");
            string extension = index > -1 ? fileName.Substring(index).Trim().ToLower() : string.Empty;

            switch (extension)
            {
                case ".jpg":
                case ".jpeg":
                    return System.Drawing.Imaging.ImageFormat.Jpeg;
                case ".gif":
                    return System.Drawing.Imaging.ImageFormat.Gif;
                case ".png":
                    return System.Drawing.Imaging.ImageFormat.Png;
                case ".bmp":
                    return System.Drawing.Imaging.ImageFormat.Bmp;
                case ".ico":
                    return System.Drawing.Imaging.ImageFormat.Icon;
                default:
                    goto case ".jpg";
            }
        }

        /// <summary>
        /// Gets the <see cref="System.Drawing.Imaging.ImageCodecInfo"/> from a specified file name.
        /// If the ImageCodecInfo is not found, it returns null.
        /// </summary>
        /// <param name="fileName">A file name.</param>
        /// <returns>
        /// The <see cref="System.Drawing.Imaging.ImageCodecInfo"/> associated with the file name 
        /// or null if the ImageCodecInfo is not found.
        /// </returns>
        public static ImageCodecInfo GetImageCodecInfo(string fileName)
        {
            if (fileName.IsNullOrEmpty())
                throw new ArgumentException("The fileName is null or empty.", "fileName");

            string extension = Path.GetExtension(fileName).ToLower();
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

            string mimeType = string.Empty;
            switch (extension)
            {
                case ".jpg":
                case ".jpeg":
                    mimeType = "image/jpeg";
                    break;
                case ".gif":
                    mimeType = "image/gif";
                    break;
                case ".png":
                    mimeType = "image/png";
                    break;
                case ".bmp":
                    mimeType = "image/bmp";
                    break;
                case ".tiff":
                    mimeType = "image/tiff";
                    break;
            }

            ImageCodecInfo ici = null;
            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.MimeType.ToLower() == mimeType)
                    ici = codec;
            }

            return ici;
        }

        /// <summary>
        /// Gets the quality <see cref="System.Drawing.Imaging.EncoderParameters"/> using the specified quality.
        /// The quality must in range [1, 100].
        /// </summary>
        /// <param name="quality">The quality must in range [1, 100].</param>
        /// <returns>
        /// The <see cref="System.Drawing.Imaging.EncoderParameters"/> associated with the specified quality.
        /// </returns>
        public static EncoderParameters GetQualityEncoderParameters(int quality)
        {
            EncoderParameters encoderParams = new EncoderParameters();
            long[] qualityParam = new long[1];
            if (quality < 0 || quality > 100)
                quality = 100;

            qualityParam[0] = quality;

            EncoderParameter encoderParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualityParam);
            encoderParams.Param[0] = encoderParam;

            return encoderParams;
        }

        /// <summary>
        /// Resize the size of image by the max width and height.
        /// </summary>
        /// <param name="size">The original size.</param>
        /// <param name="maxWidth">The max width to resize by.</param>
        /// <param name="maxHeight">The max height to resize by.</param>
        /// <returns>The <see cref="Size"/> resized.</returns>
        public static Size ResizeImage(Size size, int maxWidth, int maxHeight)
        {
            return ResizeImage(size.Width, size.Height, maxWidth, maxHeight);
        }

        /// <summary>
        /// Resize the size of image by the max width and height.
        /// </summary>
        /// <param name="width">The original width.</param>
        /// <param name="height">The original height.</param>
        /// <param name="maxWidth">The max width to resize by.</param>
        /// <param name="maxHeight">The max height to resize by.</param>
        /// <returns>The <see cref="Size"/> resized.</returns>
        public static Size ResizeImage(int width, int height, int maxWidth, int maxHeight)
        {
            int newWidth, newHeight;
            decimal w = (decimal)width;
            decimal h = (decimal)height;

            if (width > maxWidth || height > maxHeight)
            {
                if (w * maxHeight > h * maxWidth)
                {
                    newWidth = maxWidth;
                    newHeight = (int)Math.Round(h * maxWidth / w);
                }
                else
                {
                    newWidth = (int)Math.Round(w * maxHeight / h);
                    newHeight = maxHeight;
                }
            }
            else
            {
                newWidth = width;
                newHeight = height;
            }

            return new Size(newWidth, newHeight);
        }


    }
}
